package scatter.common.rest.tools;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import scatter.common.rest.serializer.*;
import scatter.common.rest.tools.calendar.CalendarUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * <p>
 * 提供常用的单例
 * </p>
 *
 * @author yangwei
 * @since 2021-08-10 10:07
 */
public class CommonSingletonTool {

	/**
	 * http 请求响应使用
	 */
	private static ObjectMapper objectMapperForHttpSingleton = null;
	/**
	 * redis cache 使用
	 */
	private static ObjectMapper objectMapperForRedisCacheSingleton = null;

	private static StringRedisSerializer stringRedisSerializerSingleton = null;
	static {
		objectMapperForHttpSingleton = newCommonObjectMapper();
		objectMapperForRedisCacheSingleton = newCommonObjectMapper();
		objectMapperForRedisCacheSingleton.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
	}

	static {
		stringRedisSerializerSingleton = new StringRedisSerializer();
	}

	/**
	 * 能用基础的objectmapper
	 * @return
	 */
	private static ObjectMapper newCommonObjectMapper(){
		ObjectMapper objectMapper = new ObjectMapper();

		objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
		objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
		objectMapper.setDateFormat(new DateFormatExtend());
		//ObjectMapper忽略多余字段
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		//LocalDateTime系列序列化和反序列化模块，继承自jsr310，我们在这里修改了日期格式
		JavaTimeModule javaTimeModule = new JavaTimeModule();
		//反序列化
		javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializerExtend(DateTimeFormatter.ofPattern(CalendarUtils.DateStyle.YYYY_MM_DD_HH_MM_SS.getValue())));
		javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(CalendarUtils.DateStyle.YYYY_MM_DD.getValue())));
		javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(CalendarUtils.DateStyle.HH_MM_SS.getValue())));
		//
		javaTimeModule.addDeserializer(Date.class, new Date2Deserializer());
		//序列化
		javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CalendarUtils.DateStyle.YYYY_MM_DD_HH_MM_SS.getValue())));
		javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(CalendarUtils.DateStyle.YYYY_MM_DD.getValue())));
		javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(CalendarUtils.DateStyle.HH_MM_SS.getValue())));
		//
		javaTimeModule.addSerializer(Date.class, new Date2Serializer());

		// 浮点型使用字符串
		objectMapper.setAnnotationIntrospector(new CustomJacksonAnnotationIntrospector());
		javaTimeModule.addSerializer(BigDecimal.class, new Decimal2Serializer());

		// 注册新的模块到objectMapper
		objectMapper.registerModule(javaTimeModule);

		return objectMapper;
	}
	/**
	 * jacson objectMapper
	 * @return
	 */
	public static ObjectMapper objectMapperForHttpSingleton(){

		return objectMapperForHttpSingleton;
	}
	/**
	 * jacson objectMapper
	 * @return
	 */
	public static ObjectMapper objectMapperForRedisCacheSingleton(){

		return objectMapperForRedisCacheSingleton;
	}
	/**
	 *
	 * @return
	 */
	public static StringRedisSerializer stringRedisSerializer(){
		return  stringRedisSerializerSingleton;
	}
}
